﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace WindSim
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, 
                     ConcurrencyMode = ConcurrencyMode.Multiple, 
                     Name = "SimulationBehavior")]
    public class Simulation : ISimulationService
    {
        //Used for locking
        private object locker = new object { };

        //Client Dictionary for storing connected clients
        private Dictionary<Client, ISimulationServiceCallback> Clients = new Dictionary<Client, 
                                                                                        ISimulationServiceCallback> { };

        //IServiceContract Interface - Methods
        #region ...
        public void RegisterClient(Guid Id, ClientType type, ModelData modelData)
    {
        ISimulationServiceCallback callback = OperationContext.Current.GetCallbackChannel<ISimulationServiceCallback>();
        lock (locker)
        {
            Clients.Add(new Client { Id = Id, Type = type }, callback);
        }
        if (type == ClientType.Model)
        {
            var destClient = Clients.Where(c => c.Key.Type == ClientType.Controller);
            var destClientValue = destClient.Select(c => c.Value).ToList();
            Action<ISimulationServiceCallback> action = callback1 => { callback1.NotifyControllerModelRegistered(Id, modelData); };
            destClientValue.ForEach(action);
        }
    }
        public void UnRegisterClient(Guid Id, ClientType type)
        {
            lock (locker)
            {
                var client = Clients.Keys.Where(c => c.Id == Id);
                Clients.Remove(client.First());
            }
            if (type == ClientType.Model)
            {
                var destClient = Clients.Where(c => c.Key.Type == ClientType.Controller);
                var destClientValue = destClient.Select(c => c.Value).ToList();
                Action<ISimulationServiceCallback> action = callback1 => { callback1.NotifyControllerModelUnregistered(Id); };
                destClientValue.ForEach(action);
            }
        }
        public List<Client> GetConnectedModels()
        {
            IEnumerable<KeyValuePair<Client, ISimulationServiceCallback>> modelsOnly;
            lock (locker)
            {
                modelsOnly = Clients.Where(c => c.Key.Type == ClientType.Model);
            }
            var clients = modelsOnly.Select(c => c.Key).ToList();
            return (List<Client>)clients;
        }
        public List<Client> GetConnectedControllers()
        {
            IEnumerable<KeyValuePair<Client, ISimulationServiceCallback>> controllersOnly;
            lock (locker)
            {
                controllersOnly = Clients.Where(c => c.Key.Type == ClientType.Controller);
            }
            var clients = controllersOnly.Select(c => c.Key).ToList();
            return (List<Client>)clients;
        }
        #endregion

        public void SetPowerStateAtModel(Guid Id, PowerState State)
        {
            var destClient = Clients.Where(c => c.Key.Id == Id);
            var destClientValue = destClient.Select(c => c.Value).ToList();
            Action<ISimulationServiceCallback> action = callback => { callback.NotifyModelPowerStateChanged(State); };
            destClientValue.ForEach(action);
        }
        public void SetFunctionStateAtModel(Guid Id, FunctionState State)
        {
            var destClient = Clients.Where(c => c.Key.Id == Id);
            var destClientValue = destClient.Select(c => c.Value).ToList();
            Action<ISimulationServiceCallback> action = callback => { callback.NotifyModelFunctionStateChanged(State); };
            destClientValue.ForEach(action);
        }
        public void SetWindDirectionAtModel(Guid Id, double DirectionAngle)
        {
            var destClient = Clients.Where(c => c.Key.Id == Id);
            var destClientValue = destClient.Select(c => c.Value).ToList();
            Action<ISimulationServiceCallback> action = callback => { callback.NotifyModelWindDirectionChanged(DirectionAngle); };
            destClientValue.ForEach(action);
        }
        public void SetWindSpeedAtModel(Guid Id, double Speed)
        {
            var destClient = Clients.Where(c => c.Key.Id == Id);
            var destClientValue = destClient.Select(c => c.Value).ToList();
            Action<ISimulationServiceCallback> action = callback => { callback.NotifyModelWindSpeedChanged(Speed); };
            destClientValue.ForEach(action);
        }
        public void SetDayTimeAtModel(Guid Id, DateTime Time)
        {
            var destClient = Clients.Where(c => c.Key.Id == Id);
            var destClientValue = destClient.Select(c => c.Value).ToList();
            Action<ISimulationServiceCallback> action = callback => { callback.NotifyModelDayTimeChanged(Time); };
            destClientValue.ForEach(action);
        }
        public void SetControlTypeAtModel(Guid Id, SimControlType ControlType)
        {
            var destClient = Clients.Where(c => c.Key.Id == Id);
            var destClientValue = destClient.Select(c => c.Value).ToList();
            Action<ISimulationServiceCallback> action = callback => { callback.NotifyModelControlTypeChanged(ControlType); };
            destClientValue.ForEach(action);
        }

        public void SendPowerStateToController(Guid Id, PowerState State)
        {
            var destClient = Clients.Where(c => c.Key.Type == ClientType.Controller);
            var destClientValue = destClient.Select(c => c.Value).ToList();
            Action<ISimulationServiceCallback> action = callback => { callback.NotifyControllerPowerStateChanged(Id, State); };
            destClientValue.ForEach(action);
        }
        public void SendFunctionStateToController(Guid Id, FunctionState State)
        {
            var destClient = Clients.Where(c => c.Key.Type == ClientType.Controller);
            var destClientValue = destClient.Select(c => c.Value).ToList();
            Action<ISimulationServiceCallback> action = callback => { callback.NotifyControllerFunctionStateChanged(Id, State); };
            destClientValue.ForEach(action);
        }
        public void SendRPMToController(Guid Id, double RPM)
        {
            var destClient = Clients.Where(c => c.Key.Type == ClientType.Controller);
            var destClientValue = destClient.Select(c => c.Value).ToList();
            Action<ISimulationServiceCallback> action = callback => { callback.NotifyControllerRPMChanged(Id, RPM); };
            destClientValue.ForEach(action);
        }
        public void SendEnergyToController(Guid Id, double Energy)
        {
            var destClient = Clients.Where(c => c.Key.Type == ClientType.Controller);
            var destClientValue = destClient.Select(c => c.Value).ToList();
            Action<ISimulationServiceCallback> action = callback => { callback.NotifyControllerEnergyChanged(Id, Energy); };
            destClientValue.ForEach(action);
        }
        public void SendNameToController(Guid Id, string Name)
        {
            var destClient = Clients.Where(c => c.Key.Type == ClientType.Controller);
            var destClientValue = destClient.Select(c => c.Value).ToList();
            Action<ISimulationServiceCallback> action = callback => { callback.NotifyControllerNameChanged(Id, Name); };
            destClientValue.ForEach(action);
        }
        public void SendLocationToController(Guid Id, string Location)
        {
            var destClient = Clients.Where(c => c.Key.Type == ClientType.Controller);
            var destClientValue = destClient.Select(c => c.Value).ToList();
            Action<ISimulationServiceCallback> action = callback => { callback.NotifyControllerLocationChanged(Id, Location); };
            destClientValue.ForEach(action);
        }
    }
}